package interpreter;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

import parser.Parser;
import parser.ParserError;
import ast.ASTTree;

import scanner.Scanner;

public class Interpreter {
    /**
     * @param args
     * @throws FileNotFoundException 
     */
    public static void main(String[] args) throws Exception {
        //should use an enum, but whatever
    	//ast nfa dfa debug
        boolean[] optPres = {false, false, false, false};

        Queue<String> tokens = new LinkedList<String>();

        String text = null;
        File script = null, file = null;

        if(args.length < 2)
            exitWithUsage();

        for(int i = 0; i<args.length; i++)
            tokens.add(args[i]);

        while(tokens.size() > 0){
            String token = tokens.remove();

            if(token.equals("-ast")){
                if(optPres[0])
                    exitWithUsage();
                optPres[0] = true;
            }
            else if(token.equals("-nfa")){
                if(optPres[1])
                    exitWithUsage();
            optPres[1] = true;
            }
            else if(token.equals("-dfa")){
                if(optPres[2])
                    exitWithUsage();
            optPres[2] = true;
            }
            else if(token.equals("-debug")){
                if(optPres[3])
                    exitWithUsage();
            optPres[3] = true;
            }
            else if(token.equals("-f")){
                if(tokens.size() > 0)
                {
                    try
                    {
                        file = new File(tokens.remove());
                        if (! file.exists())
                            exitWithError("Provided input file path is invalid or does not exist.");
                        else if (! file.canRead())
                            exitWithError("Provided input file path cannot be read.");
                    }
                    catch(Exception e)
                    {
                        exitWithError("Provided input file path is invalid.");
                    }
                }
                else
                    exitWithUsage();
            }
            else if(script == null)
            {
                script = new File(token);
                if(!script.exists()){
                    exitWithError("Provided script path does not exist.");
                }
                else if(!script.canRead()) {
                    exitWithError("Provided script path cannot be read.");
                }
            }
            else if (file == null && text == null)
            {
                text = token;
            }
            else {
                exitWithUsage();
            }
        }

        Scanner s = new Scanner(script);
        Parser p = new Parser(s);
		ASTTree ast = p.getASTTree();
		
		if(optPres[0])
			System.out.println(ast);
		
		ArrayList<ParserError> errors = p.getErrorList();
		if(!errors.isEmpty())
		{
			System.err.println(errors.size() + " error" + (errors.size() > 1 ? "s":"") +" found:\n\n");
			for(ParserError er : errors)
				System.err.println(er + "\n");
			exitWithError("\nScript not syntactically correct; cannot execute.\n");
		}
		
		if(optPres[1])
			ast.setShowNFA(true);
		if(optPres[2])
			ast.setShowDFA(true);
		if(optPres[3])
			ast.setShowDebug(true);
		
        // Calls Evaluator on Tree
		if(file != null)
			ast.run(file);
		else
			ast.run(text);
		
		System.out.println(ast.getOutput());
    }

    private static String usage() {
        return "Usage:\n  Interpreter [-ast] [-nfa] [-dfa] [-debug] script \"input text\"\n  Interpreter [-ast] [-nfa] [-dfa] [-debug] script -f inputfile";
    }

    private static void exitWithUsage() {
        System.err.println(usage());
        System.exit(1);
    }

    private static void exitWithError(String error) {
        System.err.println(error);
        System.exit(1);
    }
}
